package com.future;

import java.lang.*;
import java.util.*;

/**
 * Description:
 * 已知存在一个按非降序排列的整数数组 nums ，数组中的值不必互不相同。
 * <p>
 * 在传递给函数之前，nums 在预先未知的某个下标 k（0 <= k < nums.length）上进行了 旋转 ，使数组变为 [nums[k], nums[k+1], ..., nums[n-1], nums[0], nums[1], ..., nums[k-1]]（下标 从 0 开始 计数）。例如， [0,1,2,4,4,4,5,6,6,7] 在下标 5 处经旋转后可能变为 [4,5,6,6,7,0,1,2,4,4] 。
 * <p>
 * 给你 旋转后 的数组 nums 和一个整数 target ，请你编写一个函数来判断给定的目标值是否存在于数组中。如果 nums 中存在这个目标值 target ，则返回 true ，否则返回 false 。
 * <p>
 * 你必须尽可能减少整个操作步骤。
 * <p>
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/search-in-rotated-sorted-array-ii
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 *
 * @Author: future
 * @Date:2022/3/19:14:16
 */
public class Solution_search_81 {

    public static void main(String[] args) {

        int testTimes = 10_000;
        int maxSize = 100;
        int maxValue = 100;
        System.out.println("start");
        for (int i = 0; i < testTimes; i++) {
            int[] nums = generateRandomArr(maxSize, maxValue);
            int target = (int) ((maxValue + 1) * Math.random());
            boolean b = right(nums, target);
            boolean b2 = search(nums, target);
            if (b != b2) {
                System.out.println("right:" + b);
                System.out.println("my:" + b2);
                System.out.println("arr=" + Arrays.toString(nums));
                System.out.println("target=" + target);
                System.out.println("成功率=" + (i / testTimes));

                throw new RuntimeException();
            }
        }
        System.out.println("finish ！");
        int[] nums = {2, 5, 6, 0, 0, 1, 2};
        int target = 3;
        nums = new int[]{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1};
        target = 2;
        nums = new int[]{1, 3};
        target = 3;
        nums = new int[]{61, 64, 65, 67, 68, 68, 69, 70, 71, 73, 73, 77, 79, 83, 83, 84, 92, 94, 99, 5, 6, 10, 10, 10, 12, 17, 18, 18, 23, 24, 28, 30, 30, 30, 31, 36, 40, 40, 44, 50, 53, 57, 58, 58, 59, 60, 60};
        target = 58;
        boolean ans = search(nums, target);
        System.out.println(ans);
    }

    public static boolean search(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return false;
        }
        return process(nums, 0, nums.length - 1, target);
    }

    public static boolean process(int[] nums, int L, int R, int target) {
        if (L == R) {
            return nums[L] == target ? true : false;
        }
        int M = L + ((R - L) >> 1);
        if (nums[M] == target) {
            return true;
        }
        /**
         * eg:L=1,R=2, M=1,但是M=1时对应的值不为target,，此时答案在后半部分[L+1...R]
         */
        if (L == M) {
            return process(nums, M + 1, R, target);
        }
        /**
         * eg: nums={1,1,1,1,1,1,1,2,1,1}
         *  当 M = 4时，此时 0,...,4都是1，需要移动L
         */
        if (nums[L] == nums[M]) {
            while (L < M && nums[L] == nums[M]) {
                L++;
            }
            /**
             * 1、L,...,M都是一样
             * 2、L,...,M中有不一样的
             * 不管，反正答案在L,...,R的部分
             */
            return process(nums, L, R, target);
        }
        if (nums[L] < nums[M]) {
            /**
             * L...M递增
             */
            if (nums[L] <= target && nums[M] >= target) {
                return process(nums, L, M, target);
            } else {
                return process(nums, M + 1, R, target);
            }
        } else {
            /**
             * K点在L...M区间
             * eg: {5,6,7,1,2,3}
             * L=1，M=4时
             */
            if (nums[L] <= target || nums[M] >= target) {
                return process(nums, L, M, target);
            } else {
                return process(nums, M + 1, R, target);
            }
        }

    }

    private static boolean right(int[] nums, int target) {
        if (nums == null || nums.length == 0) {
            return false;
        }
        for (int i = 0; i < nums.length; i++) {
            if (nums[i] == target) {
                return true;
            }
        }
        return false;
    }

    private static int[] generateRandomArr(int maxSize, int maxVal) {
        int N = (int) ((maxSize + 1) * Math.random());
        if (N == 0) {
            return new int[0];
        }
        int[] nums = new int[N];
        for (int i = 0; i < N; i++) {
            nums[i] = (int) ((maxVal + 1) * Math.random());
        }
        Arrays.sort(nums);
        int k = 0;
        do {
            k = (int) ((N + 1) * Math.random());
        } while (k >= N);
        int[] ans = new int[N];
        int curIndex = 0;
        for (int i = k; i < N; i++) {
            ans[curIndex] = nums[i];
            curIndex++;
        }
        try {
            for (int i = 0; i < k; i++) {
                ans[curIndex] = nums[i];
                curIndex++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ans;
    }
}
